#include "CombinedCodeTable.h"
#include "../DiffNormUtils.h"


template<ItemSetType T>
CombinedCodeTable<T>::CombinedCodeTable() : CCCPUCodeTable<T>() {
}

// Uses prequential coding to calculate the encoded size of the db split
template<ItemSetType T>
double CombinedCodeTable<T>::CalcEncodedDbSize() {
    // m->total sum of usages in CT
    // mi->usage count of an itemset in CT
    // l->number of itemsets in CT
    uint32 l, numAlphabets, mi, nonSingletonUsgIdx;
    double dbsize, m = 0.0;
    double summationPart = 0.0;

    // We can only access the protected member of the grandfather class
    // only with `this` pointer. (class templating issue with g++)   
    numAlphabets = this->mDB->GetAlphabetSize();
    l = numAlphabets + this->mCurNumSets;
    nonSingletonUsgIdx = 0;
    
    for (uint32 i = 0; i < l; ++i) {
        if (i < numAlphabets) {
            mi = this->mAlphabet.at(i);
        } else if (this->mChangeType == ChangeAdd && i == l-1) {
            mi = this->mChangeItemUsgCount;
        } else {
            if (this->mChangeType == ChangeDel && nonSingletonUsgIdx == this->mChangeItemIdx)   ++nonSingletonUsgIdx;
            mi = this->mUsgCounts.at(nonSingletonUsgIdx++);
        } 
        
        if (mi == 0)    continue;        
        summationPart += LogDoubleFactorial(2 * mi - 1) - mi;
        m += mi;
    }
    dbsize = LogGamma(m + 0.5 * l) - LogGamma(0.5 * l) - summationPart;
    return dbsize;
}

template<ItemSetType T>
void CombinedCodeTable<T>::UseThisStuff(Database* db, ItemSetType type, CTInitType ctinit, uint32 maxCTElemLength, uint32 toMinSup) {
    CCCPUCodeTable<T>::UseThisStuff(db, type, ctinit, maxCTElemLength, toMinSup);
}

template<ItemSetType T>
uint32 CombinedCodeTable<T>::GetOldAlphabetCount(uint32 alphabetId) {
    return this->mOldAlphabet[alphabetId];
}

template<ItemSetType T>
uint32* CombinedCodeTable<T>::GetAlphabetUsage(uint32 alphabetId) {
    return this->mAbDbOccs[alphabetId].data();
}
template<ItemSetType T>
uint32 CombinedCodeTable<T>::GetSumUsageCounts() {
    uint32 mi, m = 0, nonSingletonUsgIdx = 0;
    uint32 numAlphabets = this->mDB->GetAlphabetSize();
    uint32 l = numAlphabets + this->mCurNumSets;
    
    for (uint32 i = 0; i < l; ++i) {
        if (i < numAlphabets)   mi = this->mAlphabet[i];
        else                    mi = this->mUsgCounts[nonSingletonUsgIdx++];

        m += mi;
    }
    return m;
}

template<ItemSetType T>
uint32 CombinedCodeTable<T>::GetNumItemSets() {
    return this->mDB->GetAlphabetSize() + this->mCurNumSets;
}

/* needed for defining exact class references due to templating, or else
 * we get linker error */
template class CombinedCodeTable<BM128ItemSetType>;
template class CombinedCodeTable<Uint16ItemSetType>;
template class CombinedCodeTable<BAI32ItemSetType>;